home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 007 / a86b.arc / FLOAT.DOC < prev    next >
Text File  |  1986-08-13  |  15KB  |  298 lines

  1. ---FLOAT.DOC---
  2.  
  3. In this file, we'll refer to the various Central Processing Units (CPUs)
  4. as the "86".  Thus "86" refers to either the 8088, 8086, 80186, 80286, etc.
  5. We'll refer to the various coprocessors as the "87".  Thus "87" refers to
  6. either the 8087 or the 287.
  7.  
  8.  
  9. The 8087 and 287 Coprocessors
  10.  
  11. All IBM-PC's, and most clones, contain a socket for a floating-point coprocesor.
  12. If you shell out between $80 and $400, and plug the appropriate chip into that
  13. socket, then a host of floating-point instructions is added to the assembly-
  14. language instruction set.
  15.  
  16. The original IBM-PC, and the XT, accept the original floating-point chip, the
  17. 8087.  The AT accepts a later update, the 287.  From a programming standpoint,
  18. the two chips are nearly identical: the 287 adds the instructions FSETPM and
  19. FSTSW AX, and ignores the instructions FENI and FDISI.  There is, however, a
  20. rather nasty design flaw in the 8087, that was corrected in the 287.
  21.  
  22. To understand the flaw, you must understand how the 86 and 87 work as
  23. coprocessors. Whenever the 86 sees a floating-point instruction, it
  24. communicates the instruction, and any associated memory operands, to the 87.
  25. Then the 86 goes on to its next instruction, operating in parallel with the 87.
  26. That's OK, so long as the following instructions don't do one of the following:
  27.  
  28.   1. Execute another floating point instruction; or
  29.   2. Try to read the results of the still-executing floating point instruction.
  30.  
  31. If they do, then you must provide an instruction called WAIT (or synonymously
  32. FWAIT), which halts the 86 until the 87 is finished. For almost all
  33. floating-point instructions, it should not be necessary to provide an explicit
  34. FWAIT; the 86 ought to know that it should wait.  For the 8087, it IS necessary
  35. to give an explicit FWAIT before each floating-point instruction: that is the
  36. flaw.
  37.  
  38. Because of the flaw, all assemblers supporting the 8087 will silently insert
  39. an FWAIT code (hex 9B) before all 87 instructions, except those few
  40. (the FN-instructions other than FNOP) not requiring the FWAIT. A86 provides the
  41. directive ".287", compatible with Microsoft's assembler, to signal that the
  42. 287 is the target processor.  However, the actions taken by A86 and Microsoft
  43. when seeing .287 are completely disjoint!  To wit:
  44.  
  45. * A86 ceases outputting FWAIT directives that are unneccary for the 287.  For
  46.   reasons beyond my comprehension, Microsoft continues to put them out.  I
  47.   wrote the 286/287 assembly language manual for Intel, so I'm pretty confident
  48.   that those codes aren't needed.  But I haven't bought a 287 and actually
  49.   tested the assertion.  Can someone enlighten me as to why Microsoft is
  50.   putting out those codes?
  51.  
  52. * A86 ignores the instructions FENI, FDISI, FNENI, and FNDISI after it sees
  53.   a .287 directive.  Microsoft continues to assemble these instructions.
  54.  
  55. * Microsoft recognizes the new 287 instructions, if and only if it sees the
  56.   .287 directive.  A86 recognizes them even if .287 is not given.  In general,
  57.   I don't attempt to police your instruction usage-- if you use an instruction
  58.   available on a limited number of processors, I trust that you are programming
  59.   for one of those processors.
  60.  
  61. In summary, if you have an AT with a 287, you should try the ".287" directive,
  62. and see if your programs still work.  If they do, leave the directive in: your
  63. programs will be significantly shorter than if they were assembled by
  64. Microsoft.  If your programs don't work under ".287", take away the 287, and
  65. let me know about it.
  66.  
  67.  
  68. The Floating Point Stack
  69.  
  70. The 87 has its own register set, of 8 floating-point numbers occupying 10 bytea
  71. each, plus 14 bytes of status and control information.  Many of the 87's
  72. instructions cause the numbers to act like a stack, much like a Hewlett-
  73. Packard calculator.  For this reason, the numbers are called the floating-point
  74. stack.  The standard name for the top element of the floating-point stack is
  75. either ST or ST(0); the others are named ST(1) through ST(7).  Thus, for
  76. example, the instruction to add stack element number 3 into the top stack
  77. element is usually coded FADD ST,ST(3).
  78.  
  79. I find this notation painfully verbose.  Especially bad are the parentheses,
  80. which are hard to type, and which add visual clutter to the program.  To
  81. alleviate this problem while retaining language compatibility, I name my
  82. stack elements simply 0 through 7.  I recognize ST as a synonym for 0.
  83. I allow expression elements to be concatenated; concatenation is the same as
  84. addition.  Thus, when A86 sees ST(3), it computes 0+3 = 3.  So you can code
  85. the old way, FADD ST,ST(3), or you can code the concise way, FADD 0,3 or
  86. simply FADD 3.
  87.  
  88.  
  89.  
  90. Floating Point Operand Types
  91.  
  92. The list of floating point instructions contain a variety of operand types.
  93. Here is a brief explanation of those types:
  94.  
  95. 0  stands for the top element of the floating-point stack.  A synonym for 0
  96.    is ST or ST(0).
  97.  
  98. i  stands for element number i of the floating-point stack.  i can range from
  99.    0 through 7.  A synonym for i is ST(i).
  100.  
  101. mem10r is a 10-byte memory quantity (typically declared with a DT directive)
  102.    containing a full-precision floating point number.  Intel recommends that
  103.    you NOT store your numbers in full precision; that you use the following
  104.    double precision format instead.  Full-precision numbers are intended for
  105.    storage of intermediate results (on the stack); they exist to insure
  106.    maximum accuracy for calculations on double-precision numbers, which is the
  107.    official external format of 87 numbers.
  108.  
  109. mem8r is an 8-byte memory quantity (typically declared with a DQ directive)
  110.    containing a double-precision floating-point number.  This is the best
  111.    format for floating-point numbers on the 87.  The 87 takes the same amount
  112.    of time on double-precision calculations as it does on single-precision.
  113.    The only extra time is the memory access of 4 more bytes; negligible in
  114.    comparison to the calculation time.
  115.  
  116. mem4r is a 4-byte quantity (typically defined with a DD directive) containing
  117.    a single-precision floating-point number.
  118.  
  119. mem10d is a 10-byte quantity (also defined via DT) containing a special Binary
  120.    Coded Decimal format recognized by the FBLD and FBSTP instructions.  This
  121.    format is useful for input and output of floating-point numbers.
  122.  
  123. mem4i is a 4-byte quantity representing a signed integer in two's-complement
  124.    notation.
  125.  
  126. mem2i is a 2-byte quantity representing a signed integer in two's-complement
  127.    notation.
  128.  
  129. mem14 and mem94 are 14- and 94-byte buffers containing the 87 machine state.
  130.  
  131.  
  132. Operand Choices in A86
  133.  
  134. The choice of operands for floating-point instructions seems inconsistent to me.
  135. For example, to subtract stack i from 0, you must provide two operands; to do
  136. the equivalent comparison, you must provide only one operand.  A86 smooths out
  137. these inconsistencies by allowing more choices for operands: FADD i is
  138. equivalent to FADD 0,i.  FCOM 0,i is equivalent to FCOM i.  The same holds for
  139. the other main arithmetic instructions.  FXCH 0,i and FXCH i,0 are allowed.
  140. So if you wish to retain compatibility with other assemblers, you should use
  141. their more restrictive instruction list, not the following one.
  142.  
  143.  
  144. The 87 Instruction Set
  145.  
  146. Following is the 87 instruction set.  The "w" in the opcode field is the FWAIT
  147. opcode, hex 9B, which is suppressed if .287 is selected.  Again, "0", "1", amd
  148. "i" stand for the associated floating point stack registers, not constant
  149. numbers!  Constant numbers in the descriptions are given with decimal points:
  150. 0.0, 1.0, 2.0, 10.0.
  151.  
  152.  w D9 F0     F2XM1             0 := (2.0 ** 0) - 1
  153.  w D9 E1     FABS              0 := |0|
  154.  w DE C1     FADD              0 := 1 + 0, pop
  155.  w D8 C0+i   FADD i            0 := i + 0
  156.  w DC C0+i   FADD i,0          i := i + 0
  157.  w D8 C0+i   FADD 0,i          0 := i + 0
  158.  w D8 /0     FADD mem4r        0 := 0 + mem4r
  159.  w DC /0     FADD mem8r        0 := 0 + mem8r
  160.  w DE C0+i   FADDP i,0         i := i + 0, pop
  161.  w DF /4     FBLD mem10d       push, 0 := mem10d
  162.  w DF /6     FBSTP mem10d      mem10d := 0, pop
  163.  
  164.  w D9 E0     FCHS              0 := -0
  165. 9B DB E2     FCLEX             clear exceptions
  166.  w D8 D1     FCOM              compare 0 - 1
  167.  w D8 D0+i   FCOM 0,i          compare 0 - i
  168.  w D8 D0+i   FCOM i            compare 0 - i
  169.  w D8 /2     FCOM mem4r        compare 0 - mem4r
  170.  w DC /2     FCOM mem8r        compare 0 - mem8r
  171.  w D8 D9     FCOMP             compare 0 - 1, pop
  172.  w D8 D8+i   FCOMP 0,i         compare 0 - i, pop
  173.  w D8 D8+i   FCOMP i           compare 0 - i, pop
  174.  w D8 /3     FCOMP mem4r       compare 0 - mem4r, pop
  175.  w DC /3     FCOMP mem8r       compare 0 - mem8r, pop
  176.  w DE D9     FCOMPP            compare 0 - 1, pop both
  177.  w D9 F6     FDECSTP           decrement stack pointer
  178.  w DB E1     FDISI             disable interrupts (.287 ignore)
  179.  w DE F9     FDIV              1 := 1 / 0, pop
  180.  w D8 F0+i   FDIV i            0 := 0 / i
  181.  w DC F8+i   FDIV i,0          i := i / 0
  182.  w D8 F0+i   FDIV 0,i          0 := 0 / i
  183.  w D8 /6     FDIV mem4r        0 := 0 / mem4r
  184.  w DC /6     FDIV mem8r        0 := 0 / mem8r
  185.  w DE F8+i   FDIVP i,0         i := i / 0, pop
  186.  w DE F1     FDIVR             1 := 0 / 1, pop
  187.  w D8 F8+i   FDIVR i           0 := i / 0
  188.  w DC F0+i   FDIVR i,0         i := 0 / i
  189.  w D8 F8+i   FDIVR 0,i         0 := i / 0
  190.  w D8 /7     FDIVR mem4r       0 := mem4r / 0
  191.  w DC /7     FDIVR mem8r       0 := mem8r / 0
  192.  w DE F0+i   FDIVRP i,0        i := 0 / i, pop
  193.  w DB E0     FENI              enable interrupts (.287 ignore)
  194.  w DD C0+i   FFREE i           empty i
  195.  w DE /0     FIADD mem2i       0 := 0 + mem4i
  196.  w DA /0     FIADD mem4i       0 := 0 + mem2i
  197.  w DE /2     FICOM mem2i       compare 0 - mem2i
  198.  w DA /2     FICOM mem4i       compare 0 - mem4i
  199.  w DE /3     FICOMP mem2i      compare 0 - mem2i, pop
  200.  w DA /3     FICOMP mem4i      compare 0 - mem4i, pop
  201.  w DE /6     FIDIV mem2i       0 := 0 / mem2i
  202.  w DA /6     FIDIV mem4i       0 := 0 / mem4i
  203.  w DE /7     FIDIVR mem2i      0 := mem2i / 0
  204.  w DA /7     FIDIVR mem4i      0 := mem4i / 0
  205.  w DF /0     FILD mem2i        push, 0 := mem2i
  206.  w DB /0     FILD mem4i        push, 0 := mem4i
  207.  w DF /5     FILD mem8i        push, 0 := mem8i
  208.  w DE /1     FIMUL mem2i       0 := 0 * mem2i
  209.  w DA /1     FIMUL mem4i       0 := 0 * mem4i
  210.  w D9 F7     FINCSTP           increment stack pointer
  211. 9B DB E3     FINIT             initialize 80287
  212.  w DF /2     FIST mem2i        mem2i := 0
  213.  w DB /2     FIST mem4i        mem4i := 0
  214.  w DF /3     FISTP mem2i       mem2i := 0, pop
  215.  w DB /3     FISTP mem4i       mem4i := 0, pop
  216.  w DF /7     FISTP mem8i       mem8i := 0, pop
  217.  w DE /4     FISUB mem2i       0 := 0 - mem2i
  218.  w DA /4     FISUB mem4i       0 := 0 - mem4i
  219.  w DE /5     FISUBR mem2i      0 := mem2i - 0
  220.  w DA /5     FISUBR mem4i      0 := mem4i - 0
  221.  
  222.  w D9 C0+i   FLD i             push, 0 := old i
  223.  w DB /5     FLD mem10r        push, 0 := mem10r
  224.  w D9 /0     FLD mem4r         push, 0 := mem4r
  225.  w DD /0     FLD mem8r         push, 0 := mem8r
  226.  w D9 E8     FLD1              push, 0 := 1.0
  227.  w D9 /5     FLDCW mem2i       control word := mem2i
  228.  w D9 /4     FLDENV mem14      environment := mem14
  229.  w D9 EA     FLDL2E            push, 0 := log base 2.0 of e
  230.  w D9 E9     FLDL2T            push, 0 := log base 2.0 of 10.0
  231.  w D9 EC     FLDLG2            push, 0 := log base 10.0 of 2.0
  232.  w D9 ED     FLDLN2            push, 0 := log base e of 2.0
  233.  w D9 EB     FLDPI             push, 0 := Pi
  234.  w D9 EE     FLDZ              push, 0 := +0.0
  235.  w DE C9     FMUL              1 := 1 * 0, pop
  236.  w D8 C8+i   FMUL i            0 := 0 * i
  237.  w DC C8+i   FMUL i,0          i := i : 0
  238.  w D8 C8+i   FMUL 0,i          0 := 0 * i
  239.  w D8 /1     FMUL mem4r        0 := 0 * mem4r
  240.  w DC /1     FMUL mem8r        0 := 0 * mem8r
  241.  w DE C8+i   FMULP i,0         i := i * 0, pop
  242.    DB E2     FNCLEX            nowait clear exceptions
  243.    DB E1     FNDISI            disable interrupts (.287 ignore)
  244.    DB E0     FNENI             enable interrupts (.287 ignore)
  245.    DB E3     FNINIT            nowait initialize 80287
  246.  w D9 D0     FNOP              no operation
  247.    DD /6     FNSAVE mem94      mem94 := 80287 state
  248.    D9 /7     FNSTCW mem2i      mem2i := control word
  249.    D9 /6     FNSTENV mem14     mem14 := environment
  250.    DF E0     FNSTSW AX         AX := status word
  251.    DD /7     FNSTSW mem2i      mem2i := status word
  252.  w D9 F3     FPATAN            0 := arctan(1/0), pop
  253.  w D9 F8     FPREM             0 := REPEAT(0 - 1)
  254.  w D9 F2     FPTAN             push, 1/0 := tan(old 0)
  255.  w D9 FC     FRNDINT           0 := round(0)
  256.  w DD /4     FRSTOR mem94      80287 state := mem94
  257.  w DD /6     FSAVE mem94       mem94 := 80287 state
  258.  w D9 FD     FSCALE            0 := 0 * 2.0 ** 1
  259. 9B DB E4     FSETPM            set protection mode
  260.  w D9 FA     FSQRT             0 := square root of 0
  261.  w DD D0+i   FST i             i := 0
  262.  w D9 /2     FST mem4r         mem4r := 0
  263.  w DD /2     FST mem8r         mem8r := 0
  264.  w D9 /7     FSTCW mem2i       mem2i := control word
  265.  w D9 /6     FSTENV mem14      mem14 := environment
  266.  w DD D8+i   FSTP i            i := 0, pop
  267.  w DB /7     FSTP mem10r       mem10r := 0, pop
  268.  w D9 /3     FSTP mem4r        mem4r := 0, pop
  269.  w DD /3     FSTP mem8r        mem8r := 0, pop
  270.  w DF E0     FSTSW AX          AX := status word
  271.  w DD /7     FSTSW mem2i       mem2i := status word
  272.  w DE E9     FSUB              1 := 1 - 0, pop
  273.  w D8 E0+i   FSUB i            0 := 0 - i
  274.  w DC E8+i   FSUB i,0          i := i - 0
  275.  w D8 E0+i   FSUB 0,i          0 := 0 - i
  276.  w D8 /4     FSUB mem4r        0 := 0 - mem4r
  277.  w DC /4     FSUB mem8r        0 := 0 - mem8r
  278.  
  279.  w DE E8+i   FSUBP i,0         i := i - 0
  280.  w DE E1     FSUBR             1 := 0 - 1, pop
  281.  w D8 E8+i   FSUBR i           0 := i - 0
  282.  w DC E0+i   FSUBR i,0         i := 0 - i
  283.  w D8 E8+i   FSUBR 0,i         0 := i - 0
  284.  w D8 /5     FSUBR mem4r       0 := mem4r - 0
  285.  w DC /5     FSUBR mem8r       0 := mem8r - 0
  286.  w DE E0+i   FSUBRP i,0        i := 0 - i, pop
  287.  w D9 E4     FTST              compare 0 - 0.0
  288. 9B           FWAIT             wait for 80287 ready
  289.  w D9 E5     FXAM              C3 -- C0 := type of 0
  290.  w D9 C9     FXCH              exchange 0 and 1
  291.  w D9 C8+i   FXCH 0,i          exchange 0 and i
  292.  w D9 C8+i   FXCH i            exchange 0 and i
  293.  w D9 C8+i   FXCH i,0          exchange 0 and i
  294.  w D9 F4     FXTRACT           push, 1 := expo, 0 := sig
  295.  w D9 F1     FYL2X             0 := 1 * log base 2.0 of 0, pop
  296.  w D9 F9     FYL2XP1           0 := 1 * log base 2.0 of (0+1.0), pop
  297.  
  298.